﻿// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Oliver Rau" email="mail@olira.de"/>
//     <version>$Revision: 3 $</version>
//     <created>21.08.2006 19:46</created>
// </file>

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;

using ICSharpCode.Core;

namespace ns2kml
{
	/// <summary>
	/// Description of KmlHelper.
	/// </summary>
	public class KmlHelper
	{
		public KmlHelper()
		{
		}
		
		public static void GenerateKmlRecursive(List<string> files, string targetFolder)
		{		
			if (!Directory.Exists(targetFolder))
				throw new DirectoryNotFoundException();
			
			foreach (string fileName in Directory.GetFiles(targetFolder, "*.kml")) {
				File.Delete(fileName);
			}
			
			StreamWriter sw = new StreamWriter(Path.Combine(targetFolder, "_ns2kml_master.kml"));
			WriteHeader(sw, "ns2kml Master");
			
			List<APInfo> apInfo;
			
			string targetFile, targetPath;
			
			LoggingService.InfoFormatted("Processing {0} source files", files.Count);
			
			foreach (string sourceFile in files) {
				if (Path.GetExtension(sourceFile) == ".ns1")
					apInfo = NS1FileHelper.GetInfoFromFile(sourceFile);
				else
					apInfo = WiScanFileHelper.GetInfoFromFile(sourceFile);
				
				targetFile = Path.GetFileNameWithoutExtension(sourceFile) + ".kml";
				targetPath = Path.Combine(targetFolder, targetFile);
				KmlHelper.GenerateKml(apInfo, targetPath);
				
				GeoPoint avgGp = GetAvgGeoPoint(apInfo);
				
				AppendMasterNode(sw, targetPath, apInfo.Count, avgGp);
			}
			
			WriteFooter(sw);
			sw.Flush();
			sw.Close();
		}
		
		public static void GenerateKml(List<APInfo> aps, string fileName)
		{
			LoggingService.InfoFormatted("Processing to file {0}", fileName);
			
			StreamWriter sw = new StreamWriter(fileName);
			
			WriteHeader(sw, Path.GetFileNameWithoutExtension(fileName));
			
			if (aps.Count == 0) {
				WriteFooter(sw);
				sw.Flush();
				sw.Close();
				return;
			}
			
			GeoPoint avgGp = GetAvgGeoPoint(aps);
			
			LoggingService.DebugFormatted("avgLat: {0}, avgLong: {1}, avgAlt: {2}",
			                              avgGp.Latitude.ToString(CultureInfo.InvariantCulture),
			                              avgGp.Longitude.ToString(CultureInfo.InvariantCulture),
			                              avgGp.Altitude.ToString(CultureInfo.InvariantCulture));
			
			WriteLookAt(sw, avgGp);
			
			sw.WriteLine("<Folder><name>Networks (open)</name><open>0</open>");
			
			int nr = 1;
			foreach (APInfo info in aps) {
				if (!info.HasFlag(WifiFlag.Privacy)) {
					AppendPlacemark(sw, info, nr);
				}
				nr++;
			}
			
			sw.WriteLine("</Folder>");
			sw.WriteLine("<Folder><name>Networks (encrypted)</name><open>0</open>");
			
			nr = 1;
			foreach (APInfo info in aps) {
				if (info.HasFlag(WifiFlag.Privacy)) {
					AppendPlacemark(sw, info, nr);
				}
				nr++;
			}
			
			sw.Write("</Folder>");
			WriteFooter(sw);
			
			sw.Flush();
			sw.Close();
		}
		
		#region Min, Max, Avg
		static GeoPoint[] GetMinMaxGeoPoint(List<APInfo> aps)
		{
			GeoPoint minPos = new GeoPoint(aps[0].BestPosition);
			GeoPoint maxPos = new GeoPoint(aps[0].BestPosition);
			GeoPoint bestPos;
			
			for (int i=1; i < aps.Count; ++i) {
				bestPos = aps[i].BestPosition;
				
				if (bestPos.Latitude == 0.0 || bestPos.Longitude == 0.0)
					continue;
				
				// --> check for minPos
				if (bestPos.Latitude < minPos.Latitude)
					minPos.Latitude = bestPos.Latitude;
				if (bestPos.Longitude < minPos.Longitude)
					minPos.Longitude = bestPos.Longitude;
				if (bestPos.Altitude < minPos.Altitude)
					minPos.Altitude = bestPos.Altitude;
				// <-- check for minPos
				
				// --> check for maxPos
				if (bestPos.Latitude > maxPos.Latitude)
					maxPos.Latitude = bestPos.Latitude;
				if (bestPos.Longitude > maxPos.Longitude)
					maxPos.Longitude = bestPos.Longitude;
				if (bestPos.Altitude > maxPos.Altitude)
					maxPos.Altitude = bestPos.Altitude;
				// <-- check for maxPos
			}
			
			return new GeoPoint[2] {minPos, maxPos};
		}
		
		static GeoPoint GetAvgGeoPoint(List<APInfo> aps)
		{
			GeoPoint[] minMax = GetMinMaxGeoPoint(aps);
			
			GeoPoint avg = new GeoPoint();
			
			avg.Latitude = (minMax[0].Latitude + minMax[1].Latitude) / 2;
			avg.Longitude = (minMax[0].Longitude + minMax[1].Longitude) / 2;
			avg.Altitude = (minMax[0].Altitude + minMax[1].Altitude) / 2;
			
			return avg;
		}
		#endregion Min, Max, Avg
		
		#region Methods for Master file
		static void AppendMasterNode(StreamWriter sw, string fileName, int nets, 
		                          GeoPoint pos)
		{
			string title = Path.GetFileNameWithoutExtension(fileName);
			
			sw.WriteLine("<Placemark>");
			sw.WriteLine("\t<description><![CDATA[" + 
			             "<a href=\"" + fileName + "\" title=\"" + title + "\">" + 
			             "<b>" + title + "</b></a><br />");
			sw.Write("nets:" + nets + " clat:" + pos.Latitude.ToString("#.###", CultureInfo.InvariantCulture) + 
			         " clon: " + pos.Longitude.ToString("#.##", CultureInfo.InvariantCulture));
			sw.WriteLine("]]></description>");
			sw.WriteLine("\t<name><![CDATA[Wifi-Scan: " + title + "]]></name>");
			sw.WriteLine("\t<Style><IconStyle><Icon>");
			
			sw.WriteLine("\t\t<href>c:/_Devel/_Repository/ns2kml/bin/Icons/yellow.png</href>");
			sw.WriteLine("\t\t<w>24</w>");
			sw.WriteLine("\t\t<h>24</h>");
			
			sw.WriteLine("\t</Icon></IconStyle></Style>");
			sw.WriteLine("\t<Point><coordinates>" + 
			             pos.Longitude.ToString(CultureInfo.InvariantCulture) + "," + 
			             pos.Latitude.ToString(System.Globalization.CultureInfo.InvariantCulture) + 
			             ",0</coordinates></Point>");
			sw.WriteLine("</Placemark>");
		}
		#endregion Methods for Master file
		
		#region Header / Footer
		static void WriteHeader(StreamWriter sw, string name)
		{
			sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
			sw.WriteLine("<kml xmlns=\"http://earth.google.com/kml/2.0\">");
			sw.WriteLine("<Folder><name>" + name + "</name><open>0</open>");
		}
		
		static void WriteFooter(StreamWriter sw)
		{
			sw.WriteLine("</Folder></kml>");
		}
		#endregion Header / Footer
		
		static void WriteLookAt(StreamWriter sw, GeoPoint lookAt)
		{

			
			sw.WriteLine("<LookAt>" + 
			             "<longitude>" + lookAt.Longitude.ToString(CultureInfo.InvariantCulture) + "</longitude>" + 
			             "<latitude>" +  lookAt.Latitude.ToString(CultureInfo.InvariantCulture) + "</latitude>");
			sw.WriteLine("<range>3000.00</range><tilt>45.00</tilt><heading>0</heading></LookAt>");
		}
		
		static void AppendPlacemark(StreamWriter sw, APInfo info, int nr)
		{
			if (info.BestPosition.Latitude == 0.0 || info.BestPosition.Longitude == 0.0)
				return;
			
			sw.WriteLine("<Placemark>");
			sw.WriteLine("\t<description><![CDATA[" + 
			             "                    <b>SSID :</b> " + info.SSID +
			             "<br />            <b>Vendor :</b> " + OuiHelper.Instance.GetOui(info.BSSID.Substring(0, 8)) +
			             "<br />         <b>FirstSeen :</b> " + info.FirstSeen.ToString() + 
			             "<br />          <b>LastSeen :</b> " + info.LastSeen.ToString() + 
			             "<hr />           <b>NetType :</b> " + (info.HasFlag(WifiFlag.ESS)?"Infra.":"P2P") +
			             "<br />           <b>Channel :</b> " + info.LastChannel.ToString() +
			             "<br />        <b>Encryption :</b> " + (info.HasFlag(WifiFlag.Privacy)?"yes":"no") +
			             "<br /><b>[SNR Signal Noise] :</b> " + info.MaxSNR + " " + 
			             info.MaxSignal + " " + info.MaxNoise + "]]></description>" +
			             "<br /><b>Rate:</b> " + info.DataRate);
			sw.WriteLine("\t<name><![CDATA[" + nr + "_" + info.BSSID + "]]></name>");
			sw.WriteLine("\t<Style><IconStyle><Icon>");
			
			if (info.HasFlag(WifiFlag.Privacy)) {
				sw.WriteLine("\t\t<href>c:/_Devel/_Repository/ns2kml/bin/Icons/red.png</href>");
				sw.WriteLine("\t\t<w>24</w>");
				sw.WriteLine("\t\t<h>24</h>");
			} else {
				sw.WriteLine("\t\t<href>c:/_Devel/_Repository/ns2kml/bin/Icons/green.png</href>");
				sw.WriteLine("\t\t<w>24</w>");
				sw.WriteLine("\t\t<h>24</h>");
			}
			
			sw.WriteLine("\t</Icon></IconStyle></Style>");
			sw.WriteLine("\t<Point><coordinates>" + 
			             info.BestPosition.Longitude.ToString(CultureInfo.InvariantCulture) + "," + 
			             info.BestPosition.Latitude.ToString(CultureInfo.InvariantCulture) + 
			             ",0</coordinates></Point>");
			sw.WriteLine("</Placemark>");
		}
	}
}
